package com.ag.oa.util;

import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.Security;

public class WechatUtil {

    private static final String AES = "AES";
    private static final String AES_CBC_PADDING = "AES/CBC/PKCS7Padding";

    /**
     * 开放数据校验与解密 <br/>
     * 对称解密使用的算法为 AES-128-CBC，数据采用PKCS#7填充<br/>
     * 对称解密的目标密文: encrypted=Base64_Decode(encryptData)<br/>
     * 对称解密秘钥: key = Base64_Decode(session_key),aeskey是16字节<br/>
     * 对称解密算法初始向量: iv = Base64_Decode(iv),同样是16字节<br/>
     * @param encryptedData 目标密文
     * @param sessionKey 会话ID
     * @param iv 加密算法的初始向量
     */
    public static String wxDecrypt(String encryptedData, String sessionKey, String iv) {

        String result = null;
        byte[] encrypted64 = Base64.decodeBase64(encryptedData);
        byte[] key64 = Base64.decodeBase64(sessionKey);
        byte[] iv64 = Base64.decodeBase64(iv);

        try {
            init();
            result = new String(decrypt(encrypted64, key64, generateIV(iv64)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * description: 初始化密钥
     */
    private static void init() throws Exception {

        Security.addProvider(new BouncyCastleProvider());
        KeyGenerator.getInstance(AES).init(128);
    }

    /**
     * description: 生成iv
     */
    private static AlgorithmParameters generateIV(byte[] iv) throws Exception {

        // iv 为一个 16 字节的数组，这里采用和 iOS 端一样的构造方法，数据全为0
        // Arrays.fill(iv, (byte) 0x00);
        AlgorithmParameters params = AlgorithmParameters.getInstance(AES);
        params.init(new IvParameterSpec(iv));
        return params;
    }

    /**
     * description: 执行解密操作
     * @param encryptedData  加密后的字符串
     * @param keyBytes  密钥key
     * @param iv  便宜向量iv
     */
    private static byte[] decrypt(byte[] encryptedData, byte[] keyBytes, AlgorithmParameters iv) throws Exception {

        Key key = new SecretKeySpec(keyBytes, AES);
        Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);

        // 设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        return cipher.doFinal(encryptedData);
    }

}
